/*
Package connections 使用websocket对长链接进行封装 方便与http结合
*/
package connections

import (
	"pegasus/utils"
	"sync"

	"github.com/gorilla/websocket"
)

//HubMessage 接受到的消息
type HubMessage struct {
	ID      int64
	Content []byte
}

//HubManager 链接管理器
type HubManager struct {
	utils.ILogger
	rwlocker  *sync.RWMutex
	hubs      map[int64]*Hub
	readChan  chan HubMessage
	hubCache  int
	currentID int64
}

//NewHubManager 返回管理器
func NewHubManager(il utils.ILogger, readChan chan HubMessage) *HubManager {
	hubs := &HubManager{
		ILogger:   il,
		rwlocker:  &sync.RWMutex{},
		hubs:      make(map[int64]*Hub),
		readChan:  readChan,
		hubCache:  1024,
		currentID: 0,
	}
	//go hubs.checkDead()
	return hubs
}

//SetClientQueueCache 客户端的写入队列最大数量 超过则会被丢弃
func (hm *HubManager) SetClientQueueCache(cache int) {
	if cache > 0 {
		hm.hubCache = cache
	}
}

//Add 添加1个链接 保证ID不重复
func (hm *HubManager) Add(conn *websocket.Conn) int64 {
	hm.rwlocker.Lock()
	defer hm.rwlocker.Unlock()
	var id int64
	for {
		hm.currentID = hm.currentID + 1
		id = hm.currentID
		if _, ok := hm.hubs[id]; !ok {
			break
		}
	}

	hm.hubs[id] = newHub(hm.ILogger, id, conn, hm.readChan, hm, hm.hubCache)
	hm.hubs[id].Start()
	return id
}

//Kickout 强制移除一个链接
func (hm *HubManager) Kickout(id int64) {
	hm.rwlocker.Lock()
	defer hm.rwlocker.Unlock()
	if v, ok := hm.hubs[id]; ok {
		v.Close() //关闭链接
		delete(hm.hubs, id)
	}
}

//Send 发送给指定用户
func (hm *HubManager) Send(msg *HubMessage) error {
	//长连接的话 后端处理完发送回复的时候用户可能已经下线 这是正常情况
	hm.rwlocker.RLock()
	defer hm.rwlocker.RUnlock()
	if v, ok := hm.hubs[msg.ID]; ok {
		return v.Write(msg.Content)
	}
	return nil
}

//Broadcast 广播消息 ids为空则向所有用户广播 否则向指定的用户广播
func (hm *HubManager) Broadcast(message []byte, ids ...int64) {
	hm.rwlocker.RLock()
	defer hm.rwlocker.RUnlock()
	if len(ids) == 0 {
		for _, v := range hm.hubs {
			v.Write(message)
		}
	} else {
		for _, id := range ids {
			if v, ok := hm.hubs[id]; ok {
				v.Write(message)
			}
		}
	}
}
